﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MazeNet.Communication;
using System.Drawing;

namespace MazeNetKI
{
    public class RandomKIPlayer : PlayerBase
    {
        private Random _mRandom;
        public RandomKIPlayer()
        {
            _mRandom = new Random(12345);
        }

        /// <summary>
        /// Berechnet einen Spielzug auf Basis von Zufall.
        /// </summary>
        /// <param name="_uAwaitMoveMsg">Zug Aufforderung</param>
        /// <returns>Den Spielzug</returns>
        public override MoveMessageType CalculateMove(AwaitMoveMessageType _uAwaitMoveMsg)
        {
            #region LocalVars
            MoveMessageType _lRet = new MoveMessageType();
            Point _lPlayerPos;
            List<Move> _lPossibleMoves = GenerateMoves(_uAwaitMoveMsg.board);
            Dictionary<treasureType, Point> _lTreasures;
            bool _lRandomMove = true;
            #endregion

            //Jeder mögliche Zug wird durchprobiert
            foreach (Move _lMove in _lPossibleMoves)
            {
                //Wenn der aktuelle Schatz erreichbar ist, diesen Zug wählen
                _lPlayerPos = _lMove.Board.FindPlayer(_mID);
                _lTreasures = _lMove.Board.ReachableTreasures(_lPlayerPos);
                if (_lTreasures.ContainsKey(_uAwaitMoveMsg.treasure))
                {
                    _lPlayerPos = _lTreasures[_uAwaitMoveMsg.treasure];
                    _lRet = _lMove.GenerateMoveMessage(_lPlayerPos);
                    _lRandomMove = false;
                    break;
                }
            }

            //Wenn der Schatz nicht erreichbar ist Zufällig etwas machen
            if (_lRandomMove)
            {
                Move _lMove = TrollPlayer(_lPossibleMoves).ElementAt(0).Key;
                _lRet = _lMove.GenerateMoveMessage(ChooseGoodPosition(_lMove, _uAwaitMoveMsg.treasure));
            }

            return _lRet;

        }

        private Dictionary<Move, int> TrollPlayer(List<Move> _uMoves)
        {
            Dictionary<int, Point> _lPlayerPos = null;
            Dictionary<Move, int> _lCompareMoves = new Dictionary<Move,int>();
            int _lReachableTreasures = 0;
            foreach(Move m in _uMoves)
            {
                _lPlayerPos = m.Board.FindAllPlayers();
                _lReachableTreasures = 0;
                foreach (int i in _lPlayerPos.Keys)
                {
                    if (i != _mID)
                    {
                        _lReachableTreasures += m.Board.ReachableFieldList(_lPlayerPos[i]).Count;
                    }
                }
                _lCompareMoves.Add(m, _lReachableTreasures);
            }
            _lCompareMoves.OrderBy(Move => Move.Value);
            return _lCompareMoves;
        }

        private Move ChooseRandomMove(List<Move> _uMoves)
        {
            Random r = new Random();
            return _uMoves[r.Next(0,_uMoves.Count-1)];
        }

        private Point ChooseRandomPosition(Move _uMove)
        {
            Random r = new Random();
            Point _lPlayerPos = _uMove.Board.FindPlayer(_mID);
            List<Point> _lReachable = _uMove.Board.ReachableFieldList(_lPlayerPos);
            int _lRandomReach = 0;
            bool[,] test = _uMove.Board.ReachableFields(_lPlayerPos);
            while (_lReachable.Count > 1 && _lRandomReach == 0)
            {
                _lRandomReach = r.Next(1,_lReachable.Count - 1);
            }
            _lPlayerPos = _lReachable[_lRandomReach];
            return _lPlayerPos;

        }

        private Point ChooseGoodPosition(Move _uMove, treasureType _uTreasure)
        {
            Point _lPlayerPos = _uMove.Board.FindPlayer(_mID);
            List<Point> _lReachable = _uMove.Board.ReachableFieldList(_lPlayerPos);
            Point _lTreasurePos;
            int _lBestOneDist, _lBestTwoDist, _lBestThreeDist;
            _lBestOneDist = 100;
            _lBestTwoDist = 100;
            _lBestThreeDist = 100;
            int _lCurrentDist;
            Point _lBestOneOpen, _lBestTwoOpen, _lBestThreeOpen;
            _lBestOneOpen = new Point(-1,-1);
            _lBestTwoOpen = new Point(-1,-1);
            _lBestThreeOpen = new Point(-1,-1);
            int _lOpenings;
            cardType[,] _lArr = _uMove.Board.Arr;


            _uMove.Board.FindAllTreasures().TryGetValue(_uTreasure, out _lTreasurePos);
            if (_lTreasurePos == null)
            {
                _lPlayerPos = ChooseRandomPosition(_uMove);
            }
            else
            {
                foreach (Point p in _lReachable)
                {
                    _lOpenings = 0;
                    _lCurrentDist = Math.Abs(_lTreasurePos.X - p.X) + Math.Abs(_lTreasurePos.Y - p.Y);
                    foreach (bool b in new bool[] { _lArr[p.Y, p.X].openings.top, _lArr[p.Y, p.X].openings.bottom, _lArr[p.Y, p.X].openings.left, _lArr[p.Y, p.X].openings.right })
                    {
                        ++_lOpenings;
                    }
                    switch (_lOpenings)
                    {
                        case 1:
                            if (_lCurrentDist < _lBestOneDist)
                            {
                                _lBestOneDist = _lCurrentDist;
                                _lBestOneOpen = p;
                            }
                            break;
                        case 2:
                            if (_lCurrentDist < _lBestTwoDist)
                            {
                                _lBestTwoDist = _lCurrentDist;
                                _lBestTwoOpen = p;
                            }
                            break;
                        case 3:
                            if (_lCurrentDist < _lBestThreeDist)
                            {
                                _lBestThreeDist = _lCurrentDist;
                                _lBestThreeOpen = p;
                            }
                            break;
                    }
                }
            }

            if (_lBestThreeDist < 100)
            {
                _lPlayerPos = _lBestThreeOpen;
            }
            else if (_lBestTwoDist < 100)
            {
                _lPlayerPos = _lBestTwoOpen;
            }
            else if (_lBestOneDist < 100)
            {
                _lPlayerPos = _lBestOneOpen;
            }

            return _lPlayerPos;
        }


    }
}
